
/* tree.h: заголовочный файл, содержащий функции для работы с деревом. */

#ifndef TREE_H
#define TREE_H

#include "preproc.h"
#include "multios.h"

//=====================================================================================================================================
fn_node_t*	add_node	(string, string, int, string, pth_t);					// фнкция добавления узла в дерево
void		fill_node	(fn_node_t*, int, string, string, int, string, pth_t);	// функция заполнения узла
void		free_node	(fn_node_t* node);								        // функция освобождения узла из памяти
fn_node_t*	find_node	(string);										        // функции поиска узла
fn_node_t*  del_node	(string);									        	// функция удаления узла
void		show_tree	(fn_node_t*, int, char);					        	// функция вывода дерева
void		del_tree	(fn_node_t*);								        	// функция удаления дерева
//=====================================================================================================================================
fn_node_t* add_node(string name, string fname, int argc, string desc, pth_t dll_path)	// функция добавления узла в дерево
{
	int	hash = get_hash(name);								// получение хэша имени добавляемой функции

	if(!root_tree)											// проверка существования корня (корень не существует)
	{
		root_tree = malloc(sizeof(fn_node_t));				// выделение памяти под корень дерева

		/* Вызов функции инициализации полей структуры */
		fill_node(root_tree, hash, name, fname, argc, desc, dll_path);

		return root_tree;									// возвращаем корень дерева
	}

	fn_node_t*	view = root_tree;							// описание указателя текущего узла

	while(view)												// цикл обхода дерева (пока существует указатель текущего узла)
	{
		if(hash == view->hash)								// проверка хэша текущего узла (добавляемый и текущий хэши идентичны)
			return root_tree;								// возвращаем корень дерева

		if(hash > view->hash)								// сравнение добавляемого хэша с хэшем текущего узла (добавляемый хэш больше)
		{
			if(view->right)									// проверка существования правого поддерева (правое поддерево существует)
			{
				view = (fn_node_t*) view->right;			// переход к правому поддереву
			}
			else											// правое поддерево не существует
			{
				view->right = malloc(sizeof(fn_node_t));	// выделение памяти под узел дерева

				view = (fn_node_t*) view->right;			// переход к правому поддереву

				/* Вызов функции инициализации полей структуры */
				fill_node(view, hash, name,fname, argc, desc, dll_path);

				return root_tree;							// возвращаем корень
			}
		}
		else												// добавляемый хэш меньше
		{
			if(view->left)									// проверка существования левого поддерева (левое поддерево существует)
			{
				view = (fn_node_t*)view->left;				// переход к левому поддереву
			}
			else											// левое поддерево не существует
			{
				view->left = malloc(sizeof(fn_node_t));		// выделение памяти под узел дерева

				view = (fn_node_t*) view->left;				// переход к левому поддереву

				/* Вызов функции инициализации полей структуры */
				fill_node(view, hash, name,fname, argc, desc, dll_path);

				return root_tree;							// возвращаем корень
			}
		}
	}

	return root_tree;										// возвращаем корень
}
//=====================================================================================================================================
void fill_node(fn_node_t* node, int hash, string name, string fname, int argc, string desc, pth_t dll_path)	// функция заполнения узла
{
	node->hash		= hash;					// запись хэша
	node->name		= unbind_ptr(name);		// запись имени с отвязкой от дерева
	node->fname		= unbind_ptr(fname);	// запись реального имени функции с отвязкой от дерева

	/* Проверка аргументов и запись соответствующего количества */
	node->argc		= ((argc == -1) ? MAX_ARGS : argc);

	node->desc		= unbind_ptr(desc);		// запись описания с отвязкой от дерева

	node->dll_path	= unbind_ptr(dll_path);	// запись пути с отвязкой от дерева
	node->fn		= NULL;					// инициализация указателя функции
	node->hlib		= NULL;					// инициализация указателя библиотеки

	node->right		= NULL;					// инициализация указателя правого поддерева
	node->left		= NULL;					// инициализация указателя левого поддерева

	get_fn(node);							// подгрузка библиотеки и функции
}
//=====================================================================================================================================
void free_node(fn_node_t* node)	// функция очищения узла
{
	free(node->name);			// освобождение памяти из под строки имени
	free(node->fname);			// освобождение памяти из под строки реального имени функции
	free(node->desc);			// освобождение памяти из под строки описания

	if(node->dll_path)			// проверка существования пути
	{
		free_lib(node);
		free(node->dll_path);	// освобождение памяти из под строки пути до файла
	}

	free(node);					// освобождение памяти из под узла
}
//=====================================================================================================================================
fn_node_t* find_node(string name)			// функция поиска узла дерева
{
	fn_node_t* 	view = root_tree;			// описание указтеля текущего узла
	int			hash = get_hash(name);		// описание переменной хэша искомой функции

	while(view)								// цикл обхода дерева
	{
		if(hash == view->hash)				// сравнение искомого хэша с хэшем текущего узла (хэши равны)
			return view;					// возвращаем найденный узел

		if(hash > view->hash)				// сравнение искомого хэша с хэшем текущего узлв (искомый хэш больше текущего)
			view = (fn_node_t*) view->right;// переход к правому поддереву
		else								// искомый хэш меньше
			view = (fn_node_t*) view->left;	// переход к левому поддереву
	}

	return NULL;							// возвращаем NULL, если узел не найден
}
//=====================================================================================================================================
fn_node_t* del_node(string name)							// функция удаления узла
{
	fn_node_t*	view	= find_node(name);					// описание указателя удаляемого узла
	fn_node_t*	temp	= (fn_node_t*) view->left;			// описание временного указателя для подстановки
	fn_node_t*	left	= (fn_node_t*) view->left;			// описание указателя корня левого поддерева
	fn_node_t*	right	= (fn_node_t*) view->right;			// описание указателя корня правого поддерева

	/* магия подмены значений удаляемого узла на значения коря левого поддерева */
	view->hash		= left->hash;
	view->name		= (string) left->name;

	view->argc		= left->argc;

	view->desc		= (string) left->desc;

	view->dll_path	= (string)		left->dll_path;
	view->fn		= (import_fn_t)	left->fn;
	view->hlib		= (void*)		left->hlib;
	view->left		= (fn_node_t*)	left->left;

	free(left);												// освобождение памяти от корневого узла левого поддерева

	while(TRUE)												// бесконечный цикл обхода дерева
	{
		if(temp->right)										// проверка существования правого поддереа (поддерево существует)
			temp = (fn_node_t*) temp->right;				// переход к правому поддереву
		else												// поддерево не существует
		{
			fn_node_t* tmp_right = (fn_node_t*) temp->right;// временный указатель правого поддерева (чтобы компилятор не варнингал)

			tmp_right = (fn_node_t*) right;					// подсоединение "старого" правого поддерева к правому поддереву текущего узла

			return root_tree;								// возвращаем корень
		}
	}
}
//=====================================================================================================================================
void show_tree(fn_node_t* ptr, int level, char delim)	// функция вывода дерева
{
	if(ptr)																	// проверка существования дерева
	{
		register usint i;													// счетчик

		if(ptr->right)														// проверка существования правого поддерева
			show_tree((fn_node_t*) ptr->right, level + 1, '/');				// рекурсивный вызов функции вывода для правого поддерева

			/* вывод разделителей и полей текущего узла */
		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c Hash:\t\t%i\n", delim, ptr->hash);								// вывод хэша

	#ifdef TREE_SHOW_MORE

		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c Ptr:\t\t%p\n", delim, ptr);

		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c Name:\t\t%s\n", delim, ptr->name);

		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c Fname:\t%s\n", delim, ptr->fname);

		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c Argc:\t\t%i\n", delim, ptr->argc);

		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c Desc:\t\t%s\n", delim, ptr->desc);

		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c DLL:\t\t%s\n", delim, ptr->dll_path);

		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c Func:\t\t%p\n", delim, ptr->fn);

		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c DLLPtr:\t%p\n", delim, ptr->hlib);

		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c Right:\t%p\n", delim, ptr->right);

		for (i = 0; i < level; ++i)											// цикл вывода разделителей в количестве, равном узла
			printf("|\t");													// вывод разделителя

		printf("%c Left:\t\t%p\n", delim, ptr->left);

	#endif

		if(ptr->left)														// проверка существования левого элемента
			show_tree((fn_node_t*) ptr->left, level + 1, '\\');				// рекурсивный вызов функции вывода для правого поддерева
	}
}
//=====================================================================================================================================
void show_cmds(fn_node_t* node)
{
	if(node)									// проверка существования узла
	{
		if((fn_node_t*) node->right)			// проверка существования правого поддерева
			show_cmds((fn_node_t*) node->right);

		printf("%s\n", node->name);

		if((fn_node_t*) node->left)				// проверка существования левого поддерева
			show_cmds((fn_node_t*) node->left);
	}
}
//=====================================================================================================================================
void del_tree(fn_node_t* ptr)					// функция удаления дерева из памяти
{
	if(ptr)										// проверка существования дерева
	{
		if((fn_node_t*) ptr->right)				// проверка существования правого поддерева
			del_tree((fn_node_t*) ptr->right);	// рекурсивный вызов функции удаления дерева для правого поддерева

		if((fn_node_t*) ptr->left)				// проверка существования левого поддерева
			del_tree((fn_node_t*) ptr->left);	// рекурсивный вызов функции удаления дерева для левого поддерева

		free_node(ptr);							// очищение памяти, выделенной под узел
	}
}
//=====================================================================================================================================
#endif
